//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _APPS_BUSH_PARSER_CPARSER_H_
#define _APPS_BUSH_PARSER_CPARSER_H_

#include <buola/buola.h>
#include "../syntax.h"
#include "ctokenizer.h"
#include "ztokentype.h"
#include <buola/zz.h>
#include <buola/zz/zrule.h>
#include <buola/zz/zrawrule.h>
#include "cparsedword.h"
#include "cpartialmatch.h"

namespace buola { namespace bush {

class CParser
{
    enum EStatus
    {
        STATUS_OK,
        STATUS_EOIINSUITESTART,
        STATUS_EOIINSUITEEND
    };
    
public:
    struct SPartialMatch
    {
        struct SWord
        {
            bush::CWord mWord;
            int pB,pE;
        };
        
        std::vector<SWord> mWords;
        
    };

    struct SSmallStmt
    {
        enum EType
        {
            EXPR,
            SHELL,
            OTHER
        };
        
        SSmallStmt(EType pType,TTokenIt pB,TTokenIt pE)
            :   mType(pType)
            ,   mB(pB)
            ,   mE(pE)
        {}
        
        EType mType;
        TTokenIt mB;
        TTokenIt mE;
    };

    struct SListStmt
    {
        std::vector<SSmallStmt> mStmts;
        std::vector<EToken> mSeparators;
    };
    
    CParser();
    
private:
    void CreateGrammar();
    void ExpandAliases(std::vector<CToken> &pTokens,const std::set<std::wstring> &pAlready=std::set<std::wstring>());
    
public:
    //tokens must be provided from the outside because the pipeline will contain pointers to it
    PPipeline ParseShellLine(const std::wstring &pLine,std::vector<CToken> &pTokens);
    EParseResult ParseLine(const std::wstring &pLine,std::wstring &pParsedLine,std::vector<int> &pIndent,ERunMode pRunMode);
    bool ParseAlias(CAlias &pAlias);
    void ParsePartial(std::wstring::const_iterator pB,std::wstring::const_iterator pE,CPartialMatch &pMatch);

    CTokenizer &GetTokenizer()      {   return mTokenizer;  }
    
private:
    void AppendQuoted(std::wstring::const_iterator pB,std::wstring::const_iterator pE,std::wstring &pDst);
    void AppendTransQuoted(std::wstring::const_iterator pB,std::wstring::const_iterator pE,std::wstring &pDst);
    void AppendInvertedString(const CToken &pToken,std::wstring &pDst);
    void AppendGlobString(const CToken &pToken,std::wstring &pDst);
    void AppendEnvString(const CToken &pToken,std::wstring &pDst);
    bool ShouldParseAsShell(const SSmallStmt &pS);
    void AppendPythonTokens(TTokenIt pB,TTokenIt pE,std::wstring &pDst,int &pIndent);
    void GenerateParsedLine(std::wstring &pParsedLine,const std::vector<CToken> &pTokens);
    
private:    
    CTokenizer mTokenizer;
    
    typedef ZTokenType<false> tSkipper;
    
    typedef zz::ZRule<TTokenIt,UUnused,tSkipper> tPythonRule;
    
    //python grammar
    tPythonRule rSingleInput;
    tPythonRule rFileInput;
    tPythonRule rEvalInput;
    
    tPythonRule rDecorator;
    tPythonRule rFuncDef;
    tPythonRule rParameters;
    tPythonRule rOptionalEqualTest;
    tPythonRule rTypedArgsList;
    tPythonRule rTFPDef;
    tPythonRule rVarArgsList;
    tPythonRule rVFPDef;
    
    tPythonRule rStmt;
    tPythonRule rSimpleStmt;
    tPythonRule rSmallStmt;
    tPythonRule rExprStmt;
    tPythonRule rTestListStarExpr;

    tPythonRule rDelStmt;
    tPythonRule rFlowStmt;
    tPythonRule rReturnStmt;
    tPythonRule rRaiseStmt;

    tPythonRule rImportStmt;
    tPythonRule rImportName;
    tPythonRule rImportFrom;
    tPythonRule rImportAsName;
    tPythonRule rDottedAsName;
    tPythonRule rImportAsNames;
    tPythonRule rDottedAsNames;
    tPythonRule rDottedName;

    tPythonRule rGlobalStmt;
    tPythonRule rNonlocalStmt;
    tPythonRule rAssertStmt;
    
    tPythonRule rCompoundStmt;
    tPythonRule rElseStmt;
    tPythonRule rIfStmt;
    tPythonRule rWhileStmt;
    tPythonRule rForStmt;
    tPythonRule rFinallyStmt;
    tPythonRule rTryStmt;
    tPythonRule rWithStmt;
    tPythonRule rWithItem;
    tPythonRule rExceptClause;
    tPythonRule rSuite;
    
    tPythonRule rTest;
    tPythonRule rTestNoCond;
    tPythonRule rLambDef;
    tPythonRule rLambDefNoCond;
    
    tPythonRule rBoolTest;
    tPythonRule rNotTest;
    tPythonRule rComparison;
    tPythonRule rCompOp;
    tPythonRule rStarExpr;
    tPythonRule rExpr; //binary expression
    tPythonRule rUExpr; //unary expression

    tPythonRule rAtom;
    tPythonRule rTestListComp;
    tPythonRule rTrailer;
    tPythonRule rSubscriptList;
    tPythonRule rSubscript;
    tPythonRule rSliceOp;
    tPythonRule rExprList;

    tPythonRule rTestList;
    tPythonRule rDictOrSetMaker;
    tPythonRule rClassDef;
    tPythonRule rArgList;
    tPythonRule rArgument;
    
    tPythonRule rCompIter;
    tPythonRule rCompFor;
    tPythonRule rCompIf;
    
    tPythonRule rYieldExpr;

    tPythonRule rShellStmt;
    tPythonRule rListStmt;
    
    //shell grammar
    zz::ZRule<TTokenIt,PPipeline,tSkipper> rShellInput;

    zz::ZRule<TTokenIt> rShellSinglePythonSubExpr;
    zz::ZRule<TTokenIt> rShellMultiPythonSubExpr;
    zz::ZRule<TTokenIt,CParsedWord> rShellSingleWord;
    zz::ZRule<TTokenIt,CParsedWord> rShellMultiWord;
    zz::ZRule<TTokenIt,CParsedWord> rShellMultiWordNoComma;
    zz::ZRule<TTokenIt,CParsedWord> rShellBraceExpr;
    
    zz::ZRule<TTokenIt,PRedirection,tSkipper> rShellRedirection;
    zz::ZRule<TTokenIt,PCommand,tSkipper> rShellCmd;
    zz::ZRule<TTokenIt,PPipeline,tSkipper> rShellPipeline;
    
    SListStmt mCurrentListStmt;
    std::vector<SListStmt> mListStmts;
    
    EStatus mParserStatus;
};

/*namespace bush*/ } /*namespace buola*/ }

#endif
